package com.ruoyi.swla2.util;

import cn.hutool.core.io.FileUtil;
import org.locationtech.jts.geom.Coordinate;
import org.locationtech.jts.geom.*;
import org.locationtech.jts.io.ParseException;
import org.locationtech.jts.io.WKTReader;

import java.io.File;
import java.util.List;


public class JtsUtils {
    public static final double EARTH_RADIUS = 6371.393;    // 球面余弦定理计算,地球半径，单位千米
    private static final double VINCENTY_EARTH_RADIUS = 6378.137; // Vincenty公式计算,地球半径，单位千米
    public static final double HAVERSINE_EARTH_RADIUS = 6371.393;    // Haversine公式计算,地球半径，单位千米

    /**
     * 球面余弦定理计算
     *
     * @param long1
     * @param lat1
     * @param long2
     * @param lat2
     * @return
     */
    public static double getDistance(double long1, double lat1, double long2, double lat2) {
        long1 = Math.toRadians(long1);
        long2 = Math.toRadians(long2);
        lat1 = Math.toRadians(lat1);
        lat2 = Math.toRadians(lat2);
        double cos = Math.cos(lat1) * Math.cos(lat2) * Math.cos(long1 - long2) + Math.sin(lat1) * Math.sin(lat2);
        double distance = EARTH_RADIUS * Math.acos(cos);
        return distance;
    }

    /**
     * Vincenty公式 根据经纬度，计算两点间的距离
     *
     * @param longitude1 第一个点的经度
     * @param latitude1  第一个点的纬度
     * @param longitude2 第二个点的经度
     * @param latitude2  第二个点的纬度
     * @return 返回距离 单位千米
     */
    public static double getVincentyDistance(double longitude1, double latitude1, double longitude2, double latitude2) {
        // 纬度
        double lat1 = Math.toRadians(latitude1);
        double lat2 = Math.toRadians(latitude2);
        // 经度
        double lng1 = Math.toRadians(longitude1);
        double lng2 = Math.toRadians(longitude2);
        // 纬度之差
        double a = lat1 - lat2;
        // 经度之差
        double b = lng1 - lng2;
        // 计算两点距离的公式
        double s = 2 * Math.asin(Math.sqrt(Math.pow(Math.sin(a / 2), 2) +
                Math.cos(lat1) * Math.cos(lat2) * Math.pow(Math.sin(b / 2), 2)));
        // 弧长乘地球半径, 返回单位: 千米
        s = s * VINCENTY_EARTH_RADIUS;
        return s;
    }

    /**
     * Haversine公式计算
     *
     * @param long1
     * @param lat1
     * @param long2
     * @param lat2
     * @return
     */
    public static double getHaversineDistance(double long1, double lat1, double long2, double lat2) {
        double radLat1 = Math.toRadians(lat1);
        double radLat2 = Math.toRadians(lat2);
        double a = radLat1 - radLat2;
        double b = Math.toRadians(long1) - Math.toRadians(long2);
        double s = 2 * Math.asin(Math.sqrt(Math.pow(Math.sin(a / 2), 2) + Math.cos(radLat1) * Math.cos(radLat2) * Math.pow(Math.sin(b / 2), 2)));
        s = s * HAVERSINE_EARTH_RADIUS;
        return s;
    }

    public static double distance(Point p1, Point p2) {
        return distance(p1.getCoordinate(), p2.getCoordinate());
    }

    public static double distance(Coordinate p1, Coordinate p2) {
        double lon1 = Math.toRadians(p1.getX());
        double lat1 = Math.toRadians(p1.getY());
        double lon2 = Math.toRadians(p2.getX());
        double lat2 = Math.toRadians(p2.getY());
        double vLon = Math.abs(lon1 - lon2);
        double vLat = Math.abs(lat1 - lat2);
        double h = haverSin(vLat) + Math.cos(lat1) * Math.cos(lat2) * haverSin(vLon);
        double distance = 1.2756274E7 * Math.asin(Math.sqrt(h));
        return distance;
    }

    private static double haverSin(double theta) {
        double v = Math.sin(theta / 2.0);
        return v * v;
    }

    public static double distance(LineString line) {
        Coordinate[] coors = line.getCoordinates();
        return distance(coors);
    }

    public static double distance(MultiLineString line) {
        Coordinate[] coors = line.getCoordinates();
        return distance(coors);
    }

    public static double distance(Coordinate[] coors) {
        double lineDist = 0.0;

        for (int i = 1; i < coors.length; ++i) {
            Coordinate coor1 = coors[i - 1];
            Coordinate coor2 = coors[i];
            if (coor1.x == coor2.x && coor1.y == coor2.y) {
                lineDist += 0.0;
            } else {
                lineDist += distance(coor1, coor2);
            }
        }

        return lineDist;
    }

    public static double distance(List<Coordinate> coors) {
        double lineDist = 0.0;

        for (int i = 1; i < coors.size(); ++i) {
            Coordinate coor1 = (Coordinate) coors.get(i - 1);
            Coordinate coor2 = (Coordinate) coors.get(i);
            if (coor1.x == coor2.x && coor1.y == coor2.y) {
                lineDist += 0.0;
            } else {
                lineDist += distance(coor1, coor2);
            }
        }

        return lineDist;
    }


    public static Geometry createGeometryByWKT(String wkt) throws ParseException {
        WKTReader reader = new WKTReader();
        Geometry geometry = reader.read(wkt);
        return geometry;
    }

    public static MultiLineString createMultiLineStringByWKT(String wkt) throws ParseException {
        WKTReader reader = new WKTReader();
        MultiLineString line = (MultiLineString) reader.read(wkt);
        return line;
    }

    public static LineString createLineStringByWKT(String wkt) throws ParseException {
        WKTReader reader = new WKTReader();
        LineString line = (LineString) reader.read(wkt);
        return line;
    }

    public static Point createPointByWKT(String pointWkt) {
        WKTReader reader = new WKTReader();
        Point point = null;

        try {
            point = (Point) reader.read(pointWkt);
        } catch (ParseException var4) {
            var4.printStackTrace();
        }

        return point;
    }

    public static Polygon createPolygonByWKT(String polygonWkt) {
        WKTReader reader = new WKTReader();
        Polygon polygon = null;

        try {
            polygon = (Polygon) reader.read(polygonWkt);
        } catch (ParseException var4) {
            var4.printStackTrace();
        }

        return polygon;
    }

    public static void main(String[] args) throws ParseException {
//        System.out.println(getDistance(113.69912432304535, 23.273582561699573, 113.69749152932823, 23.27353079842645));
//        System.out.println(getVincentyDistance(113.69912432304535, 23.273582561699573, 113.69749152932823, 23.27353079842645));
//        System.out.println(getHaversineDistance(113.69912432304535, 23.273582561699573, 113.69749152932823, 23.27353079842645));
//        System.out.println(distance(createMultiLineStringByWKT("MULTILINESTRING((113.69912432304535 23.273582561699573,113.69749152932823 23.27353079842645))")));

        File file = FileUtil.file("C:\\Users\\1\\Desktop\\dygq_wkt.txt");
        List<String> fileLines = FileUtil.readLines(file, "UTF-8");
        fileLines.forEach(line -> {
            try {
                LineString lineString = createLineStringByWKT(line);
                System.out.println("MULTI" + lineString.toString().replace("(", "((").replace(")", "))"));
                Coordinate[] coordinates = lineString.getCoordinates();
                Coordinate start = coordinates[0];
                String startStr = "POINT(" + start.getX() + " " + start.getY() + ")";
                System.out.println(startStr);
                Coordinate end = coordinates[coordinates.length - 1];
                String endStr = "POINT(" + end.getX() + " " + end.getY() + ")";
                System.out.println(endStr);
            } catch (ParseException e) {
                throw new RuntimeException(e);
            }
        });

    }
}
